
#include "misc.hpp"

#include "callJS.hpp"

callJS * callJS :: p_obj__ = nullptr;

Napi::Object 
callJS :: Init( Napi::Env env , Napi::Object exports )
{
        Napi::Function func = DefineClass(env, "libCallJS",	{
			InstanceMethod( "setCallBack",  &callJS::setCallBack),
            InstanceMethod( "removeCallBack" , &callJS::removeCallBack )
        });

	Napi::FunctionReference* constructor = new Napi::FunctionReference();
	*constructor = Napi::Persistent(func);
	env.SetInstanceData(constructor);

	exports.Set("libscript", func);
	return exports;
}

callJS :: callJS(const Napi::CallbackInfo& info ):ObjectWrap<callJS>( info ){
    if( p_obj__ ){
        Napi::TypeError::New( info.Env() , "callJS模块已经实例化" ).ThrowAsJavaScriptException();
    }
    p_obj__ = this;
}

callJS :: ~callJS(){}


Napi::Value callJS :: setCallBack( const Napi::CallbackInfo& info)
{
    Napi::Env env = info.Env();
    auto ret = Napi::Boolean::New( env , false );
    if( info.Length() < 2 ){
        ERROR_MSG( "参数数量不足" );
        return ret;
    }
    if( info[ 0 ].IsString() == false ){
        Napi::TypeError::New( env , "回调函数名称必须是一个字符串类型" ).ThrowAsJavaScriptException();
        ERROR_MSG( "回调函数名称必须是一个字符串类型" );
        return ret;
    }
    std::string name = info[ 0 ].ToString().Utf8Value();
    if( info[ 1 ].IsFunction() == false ){
        ERROR_MSG( "回调函数参数必须是一个函数类型" );
        Napi::TypeError::New( env , "回调函数参数必须是一个函数类型" ).ThrowAsJavaScriptException();
        return ret;
    }

    Napi::FunctionReference func = Napi::Persistent( info[ 1 ].As< Napi::Function>() );
    {
        std::lock_guard< std::mutex >  LCK( m_mutex__ );
        auto rc = m_cbs__.insert( std::make_pair( name , func ) );
        if( rc.second == false ){
            ERROR_MSG( "方法已经存在" );
            Napi::TypeError::New( env , "方法已经存在" ).ThrowAsJavaScriptException();
            return ret;
        }
    }
    return Napi::Boolean::New( env , true );
}

Napi::Value 
callJS :: removeCallBack(const Napi::CallbackInfo& info) 
{
    Napi::Env env = info.Env();
    if (!info[0].IsString()) {
        Napi::TypeError::New( env , "回调函数名称必须是一个字符串类型" ).ThrowAsJavaScriptException();
        ERROR_MSG( "回调函数名称必须是一个字符串类型" );
        return Napi::Boolean::New(env, false );
    }
    std::string name = info[0].ToString().Utf8Value();
    std::lock_guard<std::mutex> LCK(m_mutex__);
    return Napi::Boolean::New(env, m_cbs__.erase(name) > 0);
}

Napi::Value 
callJS ::  clearCallbacks( const Napi::CallbackInfo& info )
{
    Napi::Env env = info.Env();

    std::unique_lock<std::mutex> lock(m_mutex__);
    for (auto& pair : m_cbs__) {
        pair.second.Reset();
    }
    m_cbs__.clear();

    return Napi::Boolean::New(env, true );
}